﻿using System;
using System.IO.Packaging;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml;
using System.Collections.Generic;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Documents;
using System.IO;

namespace UIPrototyper
{
    /// <summary>
    /// Interaction logic for MainUI.xaml
    /// </summary>
    public partial class MainUI : Window
    {
        #region Events
        public event AddedScreenToWorkflowHandler AddedScreenToWorkflow;
        public event RemovedScreenFromWorkflowHandler RemovedScreenFromWorkflow;
        #endregion

        #region Fields
        bool operate = false;
        Point startPosition;
        UserControl selectedUC = null;
        static bool draging = false;
        private ISelectable selectedItem;
        #endregion

        #region Properties
        public ISelectable SelectedItem
        {
            get { return selectedItem; }
            set
            {
                selectedItem = value;

                if (value != null)
                {
                    pygProperties.SelectedObject = value.Properties;
                    ttbDescription.Text = value.Description;

                    if (selectedItem.GetType() == typeof(Screen))
                        ScreenSelected((Screen)selectedItem);
                }
                else
                {
                    pygProperties.SelectedObject = null;
                    ttbDescription.Text = "";
                }
            }
        }

        public Grid EditionGrid
        {
            get { return BlackboardGrid; }
        }
        #endregion

        #region Overrides & Overloads
        public MainUI()
        {
            System.Windows.Forms.Application.EnableVisualStyles();
            InitializeComponent();
            pygProperties.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(pygProperties_PropertyValueChanged);
        }
        #endregion

        #region Menu Events
        private void Novo_Click(object sender, RoutedEventArgs e)
        {
            ClearProject();
        }

        private void Abrir_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();

            ofd.Filter = "All Project Files | *.xml; *.uip| XML Files| *.xml| UI Prototyper Files| *.uip";
            ofd.FilterIndex = 3;
            ofd.FileName = "Project.uip";
            ofd.DefaultExt = ".uip";

            if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                ClearProject();
                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                doc.Load(ofd.FileName);

                foreach (XmlNode node in doc.ChildNodes[0].ChildNodes[0].ChildNodes)
                {
                    Screen sc = new Screen();
                    sc.LoadXML(node);

                    ProjectSingleton.Project.Screens.Add(sc.ID, sc);
                }

                foreach (XmlNode node in doc.ChildNodes[0].ChildNodes[1].ChildNodes)
                {
                    ScreenUC sc = new ScreenUC(node.Attributes["Margin"].Value,
                        ProjectSingleton.Project.Screens[node.Attributes["ID"].Value],
                        cvsWorkflow,
                        this, Convert.ToDouble(node.Attributes["Width"].Value),
                        Convert.ToDouble(node.Attributes["Height"].Value));

                    cvsWorkflow.Children.Add(sc);

                    AddedScreenToWorkflow(sc);
                }

                tevScreens.ItemsSource = null;
                tevScreens.ItemsSource = ProjectSingleton.Project.Screens.Values;

                SetSelectedItem(ref tevScreens, tevScreens.Items[tevScreens.Items.Count - 1]);
            }
        }

        private void Salvar_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog();

            sfd.Filter = "All Project Files | *.xml; *.uip| XML Files| *.xml| UI Prototyper Files| *.uip";
            sfd.FilterIndex = 3;
            sfd.FileName = "Project.uip";
            sfd.DefaultExt = ".uip";

            if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                Package p = null;// Package.Open(sfd.FileName, System.IO.FileMode.Create);

                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                string xml = "<Project><Screens>";


                foreach (Screen s in ProjectSingleton.Project.Screens.Values)
                {
                    xml += s.GenerateXML(p);
                }

                xml += "</Screens><Workflow>";

                foreach (FrameworkElement sc in cvsWorkflow.Children)
                {
                    if (sc.GetType() == typeof(ScreenUC))
                    {
                        ScreenUC sControl = (ScreenUC)sc;
                        xml += "<Screen ID=\"" + sControl.MyScreen.ID + "\" Margin=\"" + sc.Margin.ToString() + "\" Width=\"" + sc.Width + "\" Height=\"" + sc.Height + "\" />";
                    }
                }

                xml += "</Workflow></Project>";
                doc.LoadXml(xml);
                doc.Save(sfd.FileName);
            }
        }

        private void SalvarDoc_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog();

            sfd.Filter = "All Document Files | *.rtf; *.html; *.xaml| XML Format| *.xaml| RichText Format| *.rtf| HTML Format| *.html";
            sfd.FilterIndex = 3;
            sfd.FileName = "Report.rtf";
            sfd.DefaultExt = ".rtf";

            if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                using (FileStream stream = File.OpenWrite(sfd.FileName))
                {
                    TextRange documentTextRange = new TextRange(ReportViewer.Document.ContentStart, ReportViewer.Document.ContentEnd);

                    // sniff out what data format you've got
                    string dataFormat = DataFormats.Text;
                    string ext = System.IO.Path.GetExtension(sfd.FileName);
                    if (String.Compare(ext, ".xaml", true) == 0)
                    {
                        dataFormat = DataFormats.Xaml;
                    }
                    else if (String.Compare(ext, ".rtf", true) == 0)
                    {
                        dataFormat = DataFormats.Rtf;
                    }
                    else if (String.Compare(ext, ".html", true) == 0)
                    {
                        dataFormat = DataFormats.Html;
                    }

                    documentTextRange.Save(stream, dataFormat);
                }
            }

        }

        private void Imprimir_Click(object sender, RoutedEventArgs e)
        {
            ReportViewer.Print();
        }
        #endregion

        #region General Window Events
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Blackboard.AllowDrop = true;
            cvsWorkflow.AllowDrop = true;

            foreach (ControlType ct in Enum.GetValues(typeof(ControlType)))
            {
                ListControl cc = new ListControl();

                cc.Name = Enum.GetName(typeof(ControlType), ct);
                cc.Content = Enum.GetName(typeof(ControlType), ct);
                cc.Type = ct;

                ltvControlList.Items.Add(cc);

                ltvControlList.IsEnabled = false;

                cc.MouseMove += new MouseEventHandler(ltvControlListItem_MouseMove);
            }

            Blackboard.Drop += new DragEventHandler(Blackboard_Drop);
            cvsWorkflow.Drop += new DragEventHandler(cvsWorkflow_Drop);
        }

        private void Window_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.operate = false;
        }

        private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //Blackboard.Children.Clear();
            //cvsPreview.Children.Clear();

            SalvarDoc.Visibility = Visibility.Hidden;
            Imprimir.Visibility = Visibility.Hidden;
            ReportViewer.Document = new FlowDocument();

            switch (((TabItem)((TabControl)sender).SelectedItem).Header.ToString())
            {
                case "Editar":
                    ltvControlList.IsEnabled = true;
                    pygProperties.Enabled = true;
                    ttbDescription.IsEnabled = true;
                    tevScreens.IsEnabled = true;
                    ProjectSingleton.Project.Screens.iChanged -= screenChangedHandler;
                    break;

                case "Preview":
                    ltvControlList.IsEnabled = false;
                    pygProperties.Enabled = false;
                    ttbDescription.IsEnabled = false;
                    tevScreens.IsEnabled = false;

                    screenCopy = (ScreenDictionary<string, Screen>)ProjectSingleton.Project.Screens.Copy();

                    //screenChangedHandler = new ChangedHandler(Screens_iChanged);
                    ProjectSingleton.Project.Screens.iChanged += new ChangedHandler(Screens_iChanged);//screenChangedHandler;
                    try
                    {
                        LoadScreen(((Screen)tevScreens.SelectedItem).ID);
                    }
                    catch { }
                    break;

                case "Workflow":
                    ltvControlList.IsEnabled = false;
                    pygProperties.Enabled = false;
                    ttbDescription.IsEnabled = false;
                    tevScreens.IsEnabled = true;

                    break;

                case "Report":
                    SalvarDoc.Visibility = Visibility.Visible;
                    Imprimir.Visibility = Visibility.Visible;

                    FlowDocument fd = new FlowDocument();

                    Paragraph project = new Paragraph();

                    Run title = new Run("Projeto: Nome do Projeto");                    
                    title.FontSize = 30;
                    title.FontWeight = FontWeights.Bold;
                    project.Inlines.Add(title);
                    project.Inlines.Add(new LineBreak());

                    Run description = new Run("Descrição do Projeto");
                    description.FontSize = 11;
                    project.Inlines.Add(description);
                    project.Inlines.Add(new LineBreak());

                    //---------------------Create an Image of the Workflow------------------------
                    BlockUIContainer uiContainer;
                    Image imageReport = new Image();

                    RenderTargetBitmap rtb = new RenderTargetBitmap(800, 600, 96, 96, PixelFormats.Pbgra32);
                    Rect bounds = VisualTreeHelper.GetDescendantBounds(cvsWorkflow);
                    DrawingVisual dv = new DrawingVisual();

                    using (DrawingContext ctx = dv.RenderOpen())
                    {
                        VisualBrush vb = new VisualBrush(cvsWorkflow);
                        
                        ctx.DrawRectangle(vb, null, new Rect(0, 0, 800, 600));
                    }

                    rtb.Render(dv);

                    imageReport.Source = (ImageSource)rtb;

                    uiContainer = new BlockUIContainer(imageReport);
                    //---------------------End Image Creation------------------------------------

                    fd.Blocks.Add(uiContainer);

                    ReportViewer.Document = fd;

                    foreach (Screen s in ProjectSingleton.Project.Screens.Values)
                    {
                        s.Document(ref fd);
                    }

                    break;
            }
        }
        #endregion

        #region Edit
        #region Methods
        private void ScreenSelected(Screen pScreen)
        {
            Blackboard.Children.Clear();

            leftImageBlackboard.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + pScreen.MyType.ToString() + "Left.bmp");
            rightImageBlackboard.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + pScreen.MyType.ToString() + "Right.bmp");
            middleImageBlackboard.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + pScreen.MyType.ToString() + "Middle.bmp");

            BlackboardGrid.RowDefinitions[0].Height = new GridLength(leftImageBlackboard.Source.Height);

            switch (pScreen.MyType)
            {
                case ScreenType.WebPage:
                    Blackboard.Background = Brushes.White;
                    break;
                case ScreenType.WindowsForm:
                    BrushConverter bc = new BrushConverter();
                    Blackboard.Background = (Brush)bc.ConvertFromString("#F4F7FC");
                    break;
            }

            ltvControlList.IsEnabled = true;

            if (SelectedItem != null)
            {
                if (tbcControler.SelectedItem == tbcControler)
                {
                    ltvControlList.IsEnabled = true;
                }

                foreach (FrameworkElement fe in pScreen.ControlList)
                {
                    Blackboard.Children.Add(fe);
                }
            }
            else
            {
                ltvControlList.IsEnabled = false;
            }
        }

        private void ScreenSelecting(Screen pScreen)
        {
            Image image = new Image();

            RenderTargetBitmap rtb = new RenderTargetBitmap(800, 600, 96, 96, PixelFormats.Pbgra32);
            DrawingVisual dv = new DrawingVisual();

            using (DrawingContext ctx = dv.RenderOpen())
            {
                VisualBrush vb = new VisualBrush(BlackboardGrid);

                ctx.DrawRectangle(vb, null, new Rect(0, 0, 800, 600));
            }

            rtb.Render(dv);

            image.Source = (ImageSource)rtb;

            pScreen.Image = image;
        }

        private void ClearProject()
        {
            ProjectSingleton.Project.Screens.Clear();
            selectedUC = null;
            tevScreens.ItemsSource = null;
            Blackboard.Children.Clear();
            ltvControlList.IsEnabled = false;
            pygProperties.SelectedObject = null;
            ttbDescription.Text = "";

            cvsPreview.Children.Clear();
            cvsWorkflow.Children.Clear();
        }

        private void InsertControl(ISelectable pControl)
        {
            SelectionUC sc = new SelectionUC(pControl);

            Blackboard.Children.Add((FrameworkElement)pControl);
            Blackboard.Children.Add(sc);
            ((Screen)tevScreens.SelectedItem).ControlList.Add(pControl);
            ((Screen)tevScreens.SelectedItem).ControlList.Add(sc);

            Image image = new Image();

            RenderTargetBitmap rtb = new RenderTargetBitmap(800, 600, 96, 96, PixelFormats.Pbgra32);
            DrawingVisual dv = new DrawingVisual();

            using (DrawingContext ctx = dv.RenderOpen())
            {
                VisualBrush vb = new VisualBrush(BlackboardGrid);

                ctx.DrawRectangle(vb, null, new Rect(0, 0, 800, 600));
            }

            rtb.Render(dv);

            image.Source = (ImageSource)rtb;

            ((Screen)tevScreens.SelectedItem).Image = image;
        }

        public void SetSelectedItem(ref TreeView control, object item)
        {
            try
            {
                DependencyObject dObject = control
                    .ItemContainerGenerator
                    .ContainerFromItem(item);

                ((TreeViewItem)dObject).MouseMove += new MouseEventHandler(tevScreenItems_MouseMove);
                //uncomment the following line if UI updates are unnecessary
                //((TreeViewItem)dObject).IsSelected = true;                

                MethodInfo selectMethod =
                   typeof(TreeViewItem).GetMethod("Select",
                   BindingFlags.NonPublic | BindingFlags.Instance);

                selectMethod.Invoke(dObject, new object[] { true });

            }
            catch { }
        }
        #endregion

        #region Blackboard Events
        void Blackboard_Drop(object sender, DragEventArgs e)
        {
            ControlFactory cf = new ControlFactory();
            ISelectable element = cf.CreateControl(((ListControl)e.Data.GetData(typeof(ListControl))).Type);

            ((FrameworkElement)element).Margin = new Thickness(e.GetPosition(Blackboard).X, e.GetPosition(Blackboard).Y, 0, 0);

            InsertControl(element);
        }

        private void Blackboard_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.Source.GetType() == typeof(ScreenUC) || e.Source.GetType() == typeof(SelectionUC))
            {
                this.operate = true;
                startPosition = e.GetPosition(this);
                selectedUC = (UserControl)e.Source;

                if (e.Source.GetType() == typeof(SelectionUC))
                {
                    SelectedItem = (ISelectable)((SelectionUC)selectedUC).AssociatedControl;
                }
                else
                {
                    SelectedItem = ((ScreenUC)e.Source).MyScreen;
                }
            }
            else if (e.Source.GetType() == typeof(Canvas))
            {
                if ((ISelectable)tevScreens.SelectedItem == null)
                    SetSelectedItem(ref tevScreens, pygProperties.SelectedObject);

                SelectedItem = (ISelectable)tevScreens.SelectedItem;
            }
        }

        private void Blackboard_MouseMove(object sender, MouseEventArgs e)
        {
            if (operate && selectedUC != null)
            {
                if (selectedUC.GetType() == typeof(SelectionUC))
                    ((SelectionUC)selectedUC).Move(e.GetPosition(this), ref this.startPosition);
                else
                    ((ScreenUC)selectedUC).Move(e.GetPosition(this), ref this.startPosition);
            }
        }
        #endregion

        #region ltvControlList Drag Events
        void ltvControlListItem_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed & !draging)
            {
                draging = true;
                DragDrop.DoDragDrop(ltvControlList, sender, DragDropEffects.Copy);
                e.MouseDevice.SetCursor(Cursors.Hand);
            }
            else
            {
                draging = false;
            }
        }
        #endregion

        #region Context Menu Events
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (tevScreens.SelectedItem != null || ((MenuItem)e.Source).Header.ToString() == "Nova Tela")
            {
                switch (((MenuItem)e.Source).Header.ToString())
                {
                    case "Nova Tela":
                        Screen newScreen = new Screen();
                        newScreen.ID = "Tela" + ProjectSingleton.Project.Screens.Count.ToString();
                        newScreen.Name = "Nova Tela";
                        ProjectSingleton.Project.Screens.Add(newScreen.ID, newScreen);
                        tevScreens.ItemsSource = null;
                        tevScreens.ItemsSource = ProjectSingleton.Project.Screens.Values;
                        SetSelectedItem(ref tevScreens, newScreen);
                        break;

                    case "Delete":
                        //ProjectSingleton.Project.Screens.Remove(((Screen)tevScreens.SelectedItem).ID);
                        //tevScreens.ItemsSource = null;
                        //tevScreens.ItemsSource = ProjectSingleton.Project.Screens.Values;
                        //Blackboard.Children.Clear();
                        break;
                }
            }

            if (tevScreens.Items.Count == 0)
            {
                SelectedItem = null;
            }
        }
        #endregion

        #region TreeView Events
        private void tevScreens_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (e.OldValue != null)
            {
                ScreenSelecting((Screen)e.OldValue);
            }

            if (tevScreens.Items.Count > 0)
            {
                SelectedItem = (ISelectable)e.NewValue;
            }
        }

        private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
        {
            SelectedItem = (ISelectable)tevScreens.SelectedItem;
        }
        #endregion

        #region Description TextBox Events
        private void ttbDescription_TextChanged(object sender, TextChangedEventArgs e)
        {
            SelectedItem.Description = ((TextBox)sender).Text;
        }
        #endregion

        #region Property Grid Events
        void pygProperties_PropertyValueChanged(object s, System.Windows.Forms.PropertyValueChangedEventArgs e)
        {
            if (((System.Windows.Forms.PropertyGrid)s).SelectedObject.GetType() == typeof(ScreenProperties))
            {
                Screen sc = (Screen)tevScreens.SelectedItem;

                tevScreens.ItemsSource = null;
                tevScreens.ItemsSource = ProjectSingleton.Project.Screens.Values;

                SetSelectedItem(ref tevScreens, sc);
            }
        }
        #endregion
        #endregion

        #region Preview
        ScreenDictionary<string, Screen> screenCopy;
        List<Screen> screensViewed;
        int actualPosition;
        string actualScreen;
        ChangedHandler screenChangedHandler;

        private void LoadScreen(string pScreenID)
        {
            try
            {
                Screen screen = screenCopy[pScreenID];
                actualScreen = pScreenID;

                //screensViewed.Insert(actualPosition + 1, screen);
                //actualPosition = screensViewed.Count - 1;

                cvsPreview.Children.Clear();

                leftImagePreview.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + ProjectSingleton.Project.Screens[pScreenID].MyType.ToString() + "Left.bmp");
                rightImagePreview.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + ProjectSingleton.Project.Screens[pScreenID].MyType.ToString() + "Right.bmp");
                middleImagePreview.Source = (ImageSource)(new ImageSourceConverter()).ConvertFrom("Images\\" + ProjectSingleton.Project.Screens[pScreenID].MyType.ToString() + "Middle.bmp");

                switch (ProjectSingleton.Project.Screens[pScreenID].MyType)
                {
                    case ScreenType.WebPage:
                        cvsPreview.Background = Brushes.White;
                        break;
                    case ScreenType.WindowsForm:
                        BrushConverter bc = new BrushConverter();
                        cvsPreview.Background = (Brush)bc.ConvertFromString("#F4F7FC");
                        break;
                }

                PreviewGrid.RowDefinitions[0].Height = new GridLength(leftImagePreview.Source.Height);

                foreach (FrameworkElement fe in screen.ControlList)
                {
                    if (fe.GetType() != typeof(SelectionUC))
                    {
                        cvsPreview.Children.Add(fe);

                        if (fe.GetType() == typeof(CustomButton))
                        {
                            ((CustomButton)fe).Click += new RoutedEventHandler(Button_Click);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (((ButtonProperties)((CustomButton)sender).Properties).ScreenID != "")
                LoadScreen(((ButtonProperties)((CustomButton)sender).Properties).ScreenID);
        }

        void Screens_iChanged(IChanged changedObject)
        {
            if (changedObject.GetType() == typeof(Screen))
            {
                screenCopy[((Screen)changedObject).ID] = (Screen)((Screen)changedObject).Copy();

                if (((Screen)changedObject).ID == actualScreen)
                    LoadScreen(actualScreen);
            }
        }
        #endregion

        #region Workflow
        void tevScreenItems_MouseMove(object sender, MouseEventArgs e)
        {
            if (tbcControler.SelectedItem == tbiWorkflow)
            {
                if (e.LeftButton == MouseButtonState.Pressed & !draging)
                {
                    draging = true;
                    DragDrop.DoDragDrop(tevScreens, sender, DragDropEffects.Copy);
                    e.MouseDevice.SetCursor(Cursors.Hand);
                }
                else
                {
                    draging = false;
                }
            }
        }

        void cvsWorkflow_Drop(object sender, DragEventArgs e)
        {
            Screen screen = ((Screen)((StackPanel)e.Data.GetData(typeof(StackPanel))).DataContext);

            ScreenUC sc = new ScreenUC((new Thickness(e.GetPosition(cvsWorkflow).X, e.GetPosition(cvsWorkflow).Y, 0, 0)).ToString(), screen, cvsWorkflow, this);

            cvsWorkflow.Children.Add(sc);

            AddedScreenToWorkflow(sc);
        }
        #endregion
    }
}
